package services

import (
	"errors"
	"fmt"
	"math/rand"
	"strconv"
	"time"

	"cashew.com/cashew_api/dtos"
	"cashew.com/cashew_api/models"
	"cashew.com/cashew_common/configs"
	"cashew.com/cashew_common/constants"
	"cashew.com/cashew_common/utils"
	"github.com/beego/beego/v2/client/orm"
	"github.com/beego/beego/v2/core/logs"
)

var Redisserver *utils.RedisService

func init() {
	Redisserver = new(utils.RedisService)
}

// 初始化用户信息函数拆分
func InitializeUserInfo(req *dtos.WsConnectParams, subRegionId int) error {
	imChatFreeCount, _ := strconv.Atoi(configs.ImChatFreeCount)
	user := models.Users{
		UserId:        req.UserId,
		Gender:        req.Gender,
		SubRegionId:   subRegionId,
		Status:        constants.ANCHOR_ONLINEIDLE,
		UpdateTime:    time.Now().Unix(),
		Nick:          req.Nick,
		HeadImg:       req.HeadImg,
		Age:           req.Age,
		FreeChatCount: imChatFreeCount, // 需要确保imChatFreeCount已正确获取
	}
	if req.HeadImg == "null" {
		user.HeadImg = ""
	}
	_, err := models.AddUsers(&user)
	if err != nil {
		return err // 返回错误供上层处理
	}
	return nil
}

// 更新用户信息函数
func UpdateUserInfo(req *dtos.WsConnectParams, subRegionId int) (err error) {
	// 更新用户信息，在线状态改成在线空闲
	user := models.Users{
		UserId:      req.UserId,
		SubRegionId: subRegionId,
		Status:      constants.ANCHOR_ONLINEIDLE,
		UpdateTime:  time.Now().Unix(),
	}
	updateFields := []string{"sub_region_id", "status", "update_time"}
	// 如果昵称不为空，更新昵称
	if req.Nick != "" {
		user.Nick = req.Nick
		updateFields = append(updateFields, "nick")
	}
	// 如果头像不为空，更新头像
	if req.HeadImg != "" && req.HeadImg != "null" {
		user.HeadImg = req.HeadImg
		updateFields = append(updateFields, "head_img")
	}
	if req.Age != 0 {
		user.Age = req.Age
		updateFields = append(updateFields, "age")
	}
	if req.Gender != 0 {
		user.Gender = req.Gender
		updateFields = append(updateFields, "gender")
	}
	err = models.UpdateUsersByUserIdAndFields(&user, updateFields)
	if err != nil {
		return
	}

	return
}

// 更新主播信息函数
func UpdateAnchorInfo(req *dtos.WsConnectParams, subRegionId int) (err error) {
	anchor := models.Anchor_info{
		AnchorId:    req.UserId,
		SubRegionId: subRegionId,
		Status:      constants.ANCHOR_ONLINEIDLE,
	}
	updateFields := []string{"sub_region_id", "status"}
	// 如果昵称不为空，更新昵称
	if req.Nick != "" {
		anchor.Nick = req.Nick
		updateFields = append(updateFields, "nick")
	}
	// 如果头像不为空，更新头像
	if req.HeadImg != "" && req.HeadImg != "null" {
		anchor.HeadImg = req.HeadImg
		updateFields = append(updateFields, "head_img")
	}
	if req.Age != 0 {
		anchor.Age = req.Age
		updateFields = append(updateFields, "age")
	}

	if req.Gender != 0 {
		anchor.Gender = req.Gender
		updateFields = append(updateFields, "gender")
	}
	err = models.UpdateAnchor_infoByAnchorIdAndFields(&anchor, updateFields)
	if err != nil {
		return
	}

	return
}

type AnchorMatchingTaskReq struct {
	UserId int64 `json:"user_id"`
}

func GetRandomUserInfoAndAcquireLock(userId int64) (v *models.Anchor_info, err error) {
	userIds, err := models.GetOnlineTakingOrderAnchorIds(userId)
	if err != nil {
		return nil, err
	}
	if len(userIds) == 0 {
		return nil, fmt.Errorf("没有可接单主播")
	}

	//rand.Seed(time.Now().UnixNano())
	// 打乱用户ID切片顺序，方便随机选取
	for i := 0; i < len(userIds); i++ {
		j := rand.Intn(len(userIds))
		userIds[i], userIds[j] = userIds[j], userIds[i]
	}

	var RandomAnchorId int64
	for _, userId := range userIds {
		userIdstr := fmt.Sprintf("%v", userId)
		can, err := Redisserver.AcquireCallUserLock(userIdstr, 30)
		if err != nil {
			return nil, err
		}
		if can {
			RandomAnchorId = userId
			break
		}
	}

	// 根据随机到的主播id获取主播信息
	v, err = models.GetAnchor_infoByAnchorId(RandomAnchorId)
	if err != nil {
		_ = Redisserver.ReleaseCallUserLock(fmt.Sprintf("%v", RandomAnchorId))
		return nil, err
	}
	return v, nil
}

func StopCallLogic(guid int64, userId int64, anchorId int64, viewerId int64, callerId int64, operationType int) (err error) {
	if userId != anchorId && userId != viewerId {
		return errors.New("用户非法，不是主播或用户")
	}

	toUserId := viewerId
	if userId == viewerId {
		toUserId = anchorId
	}
	strAnchorId := fmt.Sprintf("%d", anchorId)
	strViewerId := fmt.Sprintf("%d", viewerId)

	lockExists, _ := Redisserver.IsCallUserLockExists(strAnchorId)
	if lockExists {
		_ = Redisserver.ReleaseCallUserLock(strAnchorId)
		_ = Redisserver.ReleaseCallUserLock(strViewerId)
	}

	strGuid := ""
	if guid != 0 {
		strGuid = fmt.Sprintf("%d", guid)
	}
	// 通话时间
	var callDuration int64

	//identity, err := models.GetUserIdentityByUserId(userId)
	//if err != nil {
	//	logs.Error("获取用户身份失败:GetUserIdentityByUserId(%v): %v", userId, err)
	//	return err
	//}
	callerIdentity, err := models.GetUserIdentityByUserId(callerId)
	if err != nil {
		logs.Error("获取用户身份失败:GetUserIdentityByUserId(%v): %v", callerId, err)
		return err
	}

	// 判断 guid ，guid 等于0表示是未接听直接挂断
	if guid > 0 {
		// 1、根据 guid 查询 video_call_log 表中记录
		videoCallLog, err := models.GetVideo_call_logById(guid)
		if err != nil {
			logs.Error("查询 video_call_log 表中记录失败:GetVideo_call_logById(%s): %v", guid, err)
			return err
		}
		beginTime := videoCallLog.BeginTime
		logEndTime := videoCallLog.EndTime

		if logEndTime > 0 {
			logs.Error("通话已经结束，不能重复挂断")
			return errors.New("通话已经结束，不能重复挂断")
		}

		// 2、根据对聊唯一标识修改video_call_log表中记录，设置结束时间
		endTime := time.Now().Unix()
		updateParams := models.Video_call_log{
			Id:      guid,
			EndTime: endTime,
		}
		callDuration = endTime - beginTime

		err = models.UpdateVideo_call_logByIdAndFields(&updateParams, []string{"end_time"})
		if err != nil {
			logs.Error("修改 video_call_log 表中记录失败:UpdateVideo_call_logByIdAndFields(%+v): %v", updateParams, err)
			return err
		}

		// 查询主播接通前的接单状态
		anchorInfo, err := models.GetAnchor_infoByAnchorId(anchorId)
		if err != nil {
			logs.Error("查询主播信息失败:GetAnchor_infoByAnchorId(%v): %v", anchorId, err)
			return err
		}

		// 3、修改anchor_info表中status字段值为2 或 3
		anchorNew := models.Anchor_info{
			AnchorId:   anchorId,
			Status:     constants.ANCHOR_ONLINEIDLE,
			ActiveTime: time.Now().Unix(),
		}
		anchorNewFields := []string{"status", "active_time"}
		if anchorInfo.FastOrder == constants.FAST_ORDER_ON {
			anchorNew.Status = constants.ANCHOR_ONLINETAKINGORDERS
			anchorNew.FastOrder = constants.FAST_ORDER_OFF
			anchorNewFields = append(anchorNewFields, "fast_order")
		}
		err = models.UpdateAnchor_infoByAnchorIdAndFields(&anchorNew, anchorNewFields)
		if err != nil {
			logs.Error("修改 anchor_info 表中记录失败:UpdateAnchor_infoByAnchorIdAndFields(%+v): %v", anchorNew, err)
			return err
		}

		// 4、修改 user 表中status字段值为2
		users := models.Users{
			UserId:     viewerId,
			Status:     constants.ANCHOR_ONLINEIDLE,
			UpdateTime: time.Now().Unix(),
		}
		err = models.UpdateUsersByUserIdAndFields(&users, []string{"status", "update_time"})
		if err != nil {
			return err
		}

		// 调用停止计费接口

		respData, err := ChargingStop(strGuid, strAnchorId, strViewerId)
		if err != nil || respData.Code != 0 {
			logs.Error("通知开启计费报错：services.ChargingStop(%s, %s, %s) return: (respData:%+v,err:%v)", strGuid, strAnchorId, strViewerId, respData, err)
			return errors.New("通知停止计费失败")
		}
	}

	// 如果不是接通的挂断，又没锁的情况下不用发消息，防止是超时自动挂断导致消息重发问题
	if guid == 0 && !lockExists {
		return
	}

	// 查询用户信息详情【读缓存】
	anchorCacheInfo, err := GetUserInfoFromRedis(Redisserver, strAnchorId, constants.IDENTITY_ANCHOR)
	if err != nil {
		logs.Error("GetUserInfoFromRedis(%v): %v", strAnchorId, err)
		return
	}
	viewerCacheInfo, err := GetUserInfoFromRedis(Redisserver, strViewerId, constants.IDENTITY_NORMAL_USER)
	if err != nil {
		logs.Error("GetUserInfoFromRedis(%v): %v", strAnchorId, err)
		return
	}

	// 4、向mq发布挂断信息，消息订阅服务处理该条消息
	// （1）男性用户挂断则向主播发送用户已挂断消息
	// （2）主播挂断则向用户发送主播已挂断消息
	strFromUserId := fmt.Sprintf("%d", userId)
	strToUserId := fmt.Sprintf("%d", toUserId)

	// 发送 IM 消息给对方
	noticeUserId := strToUserId
	reqIm := AssembleImVideocallHangupRequest(callerIdentity, noticeUserId, strGuid, anchorId, operationType, callDuration, viewerCacheInfo, anchorCacheInfo)
	err = ImVideocallHangup(&reqIm)
	if err != nil {
		logs.Error("IM发布挂断信息失败:videocallHangup(%v, %v): %v", strFromUserId, strToUserId, err)
		return
	}

	// 发送 IM 消息给自己
	noticeUserId = strFromUserId
	reqIm2 := AssembleImVideocallHangupRequest(callerIdentity, noticeUserId, strGuid, anchorId, operationType, callDuration, viewerCacheInfo, anchorCacheInfo)
	err = ImVideocallHangup(&reqIm2)
	if err != nil {
		logs.Error("IM发布挂断信息通知自己失败:videocallHangup(%v, %v): %v", strToUserId, strFromUserId, err)
		return
	}
	return
}

func InterruptsCallLogic(guid int64, userId int64, anchorId int64, operationType int) (err error) {
	//// userId 对应的身份是普通用户
	//identity := constants.IDENTITY_NORMAL_USER
	// 通话时间
	var callDuration int64

	strUserId := fmt.Sprintf("%d", userId)
	strAnchorId := fmt.Sprintf("%d", anchorId)
	_ = Redisserver.ReleaseCallUserLock(strAnchorId)
	_ = Redisserver.ReleaseCallUserLock(strUserId)

	// 1、根据 guid 查询 video_call_log 表中记录
	videoCallLog, err := models.GetVideo_call_logById(guid)
	if err != nil {
		logs.Error("查询 video_call_log 表中记录失败:GetVideo_call_logById(%s): %v", guid, err)
		return err
	}
	beginTime := videoCallLog.BeginTime
	logEndTime := videoCallLog.EndTime
	callerId := videoCallLog.CallerId

	if logEndTime > 0 {
		logs.Error("通话已经结束，不能重复挂断")
		return errors.New("通话已经结束，不能重复挂断")
	}

	callerIdentity, err := models.GetUserIdentityByUserId(callerId)
	if err != nil {
		logs.Error("获取用户身份失败:GetUserIdentityByUserId(%v): %v", callerId, err)
		return err
	}

	// 2、根据对聊唯一标识修改video_call_log表中记录，设置结束时间
	endTime := time.Now().Unix()
	updateParams := models.Video_call_log{
		Id:      guid,
		EndTime: endTime,
	}

	callDuration = endTime - beginTime

	err = models.UpdateVideo_call_logByIdAndFields(&updateParams, []string{"end_time"})
	if err != nil {
		return
	}

	// 3、修改 user 表中status字段值为2
	users := models.Users{
		UserId:     userId,
		Status:     constants.ANCHOR_ONLINEIDLE,
		UpdateTime: time.Now().Unix(),
	}
	err = models.UpdateUsersByUserIdAndFields(&users, []string{"status", "update_time"})
	if err != nil {
		return
	}

	// 查询主播接通前的接单状态
	anchorInfo, err := models.GetAnchor_infoByAnchorId(anchorId)
	if err != nil {
		logs.Error("查询主播信息失败:GetAnchor_infoByAnchorId(%v): %v", anchorId, err)
		return err
	}

	// 3、修改anchor_info表中status字段值为2 或 3
	anchorNew := models.Anchor_info{
		AnchorId:   anchorId,
		Status:     constants.ANCHOR_ONLINEIDLE,
		ActiveTime: time.Now().Unix(),
	}

	anchorNewFields := []string{"status", "active_time"}
	if anchorInfo.FastOrder == constants.FAST_ORDER_ON {
		anchorNew.Status = constants.ANCHOR_ONLINETAKINGORDERS
		anchorNew.FastOrder = constants.FAST_ORDER_OFF
		anchorNewFields = append(anchorNewFields, "fast_order")
	}
	err = models.UpdateAnchor_infoByAnchorIdAndFields(&anchorNew, anchorNewFields)
	if err != nil {
		return
	}

	strViewerId := fmt.Sprintf("%d", userId)
	strGuid := ""
	if guid > 0 {
		strGuid = fmt.Sprintf("%d", guid)
	}

	// 查询用户信息详情【读缓存】
	anchorCacheInfo, err := GetUserInfoFromRedis(Redisserver, strAnchorId, constants.IDENTITY_ANCHOR)
	if err != nil {
		logs.Error("GetUserInfoFromRedis(%v): %v", strAnchorId, err)
		return
	}

	viewerCacheInfo, err := GetUserInfoFromRedis(Redisserver, strViewerId, constants.IDENTITY_NORMAL_USER)
	if err != nil {
		logs.Error("GetUserInfoFromRedis(%v): %v", strAnchorId, err)
		return
	}

	// 给 anchor 发送 IM 消息
	noticeUserId := strAnchorId
	reqIm := AssembleImVideocallHangupRequest(callerIdentity, noticeUserId, strGuid, anchorId, operationType, callDuration, viewerCacheInfo, anchorCacheInfo)
	err = ImVideocallHangup(&reqIm)

	if err != nil {
		return
	}

	// 给 user 发送 IM 消息
	noticeUserId = strUserId
	reqIm2 := AssembleImVideocallHangupRequest(callerIdentity, noticeUserId, strGuid, anchorId, operationType, callDuration, viewerCacheInfo, anchorCacheInfo)
	err = ImVideocallHangup(&reqIm2)
	if err != nil {
		return
	}
	return
}

// GetAnchorPriceInfo 函数根据主播ID和价格类型获取主播的价格信息。
func GetAnchorPriceInfo(anchorId int64, priceType int) (priceInfo *dtos.AnchorPriceInfoRes, err error) {
	videoCallPrice, err := models.GetVideo_call_priceByAnchorId(anchorId, priceType)
	if err != nil {
		return nil, err
	}

	if videoCallPrice == nil || videoCallPrice.Price == 0 {
		return nil, errors.New("价格信息不存在")
	}

	videoCallPriceConfig, err := models.GetVideo_call_price_configById(videoCallPrice.Price)
	if err != nil || videoCallPriceConfig == nil || videoCallPriceConfig.PayPrice == 0 {
		return
	}

	return &dtos.AnchorPriceInfoRes{
		PriceType:   videoCallPriceConfig.PriceType,
		PayPrice:    videoCallPriceConfig.PayPrice,
		AnchorPrice: videoCallPriceConfig.AnchorPrice,
	}, nil
}

type CheckMaleCallCostRes struct {
	Checked     bool
	FreeCallNum int64
	PayPrice    int64
	AnchorPrice int64
}

// 如果是男性判断至少有1分钟使用的金币余额(或有免费通话卡)
func CheckMaleCallCost(viewerId, anchorId int64) (res *CheckMaleCallCostRes, err error) {
	res = &CheckMaleCallCostRes{}
	res.Checked = true
	// 获取女主播单价
	priceInfo, err := GetAnchorPriceInfo(anchorId, constants.PRICE_TYPE_ID_VIDEO_CALL)
	if err != nil {
		logs.Error("GetAnchorPriceInfo(%v, %v): %v", anchorId, constants.PRICE_TYPE_ID_VIDEO_CALL, err)
		res.Checked = false
		return
	}

	payPrice := priceInfo.PayPrice
	anchorPrice := priceInfo.AnchorPrice

	res.PayPrice = payPrice
	res.AnchorPrice = anchorPrice

	// 判断是否有免费通话卡
	freeCallNum, err := models.CountAvailableCallsByUserId(viewerId)
	if err != nil {
		logs.Error("CountAvailableCallsByUserId(%v): %v", viewerId, err)
		res.Checked = false
		return
	}
	res.FreeCallNum = freeCallNum

	if freeCallNum > 0 {
		res.Checked = true
		return
	}

	// 获取用户金币余额
	respData, err := GetCocoUserbalance(fmt.Sprintf("%d", viewerId))
	if err != nil {
		logs.Error("调用coco接口获取用户金币余额报错：services.GetCocoUserbalance(%d): %v", viewerId, err)
		res.Checked = false
		return
	}
	if respData.Result != 0 {
		logs.Error("调用coco接口获取用户金币余额报错：services.GetCocoUserbalance(%d): %v", viewerId, respData)
		res.Checked = false
		return res, errors.New("非法用户")
	}

	userBalance, _ := strconv.ParseInt(respData.Data.Balance, 10, 64)
	if userBalance < payPrice {
		res.Checked = false
		return
	}

	return
}

// 根据用户id,获取不在用户黑名单中的在线可接单主播列表 userId:用户id,isRegion:是否按区域筛选 0:不按区域筛选 1:按区域筛选 2:筛选不在同一区域的主播
func GetOnlineTakingOrderAnchorsByUserId(userId int64, isRegion int, userSubRegionId int) (v []AnchorInfo, err error) {

	// 1. 查询用户的黑名单列表
	blackIds, err := models.GetBlackAnchorIdsByUserId(userId)
	if err != nil {
		return nil, err
	}

	o := orm.NewOrm()
	// 查询符合条件的主播数量，排除黑名单中的主播
	sql := `SELECT anchor_id,sub_region_id,status FROM anchor_info WHERE status IN (2, 3) AND disable_status = 0 AND live_model != 2`

	if isRegion == 1 {
		sql += " AND sub_region_id = " + fmt.Sprintf("%d", userSubRegionId)
	} else if isRegion == 2 {
		sql += " AND sub_region_id != " + fmt.Sprintf("%d", userSubRegionId)
	}

	if len(blackIds) > 0 {
		blackIdsStr := SliceToString(blackIds)
		sql += " AND anchor_id NOT IN (" + blackIdsStr + ") "
	}

	sql += " LIMIT 1000"
	_, err = o.Raw(sql).QueryRows(&v)
	if err != nil {
		return nil, err
	}

	return
}

// 免费卡信息，用户是否是免费卡通话，免费通话卡时间
func CheckFreeCallCard(userId int64) (freeCallNum int64, freeCallCardTime int, err error) {
	freeCallNum, err = models.CountAvailableCallsByUserId(userId)
	if err != nil {
		return 0, 0, err
	}

	res, err := models.GetSystem_configsByType(constants.SYS_CONFIG_TYPE_FREE_CALL_USE_TIME)
	if err != nil {
		return 0, 0, err
	}
	if res != nil {
		freeCallCardTime, _ = strconv.Atoi(res.Value)
	}

	return
}
